/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.draw;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.commons.view.DrawingArea;
import br.ufmg.dees.insane.prep.MapElement;
import br.ufmg.dees.insane.prep.MapNode;

public class MapElementDraw extends ElementDraw {
	
//*****************************************************************************
	
	public MapElementDraw(DrawingArea da, Object represents) {
		super(da, represents);
		MapNode[] conec = ((MapElement)represents).getConnectivite();
		Point p1 = da.getViewPoint(conec[0]);
		this.setLocation(p1);
	}
	
//*****************************************************************************
	
    /**
     * Draws labels in a given Graphics.
     *
     * @see   java.awt.Graphics
     */
	public void drawLabel(Graphics2D g2) {
		MapElement me = (MapElement)getRepresents();
		GeneralPath element = getElement();
		if ( element.contains(mediumX,mediumY) ) {
			g2.drawString( "E" + me.getLabel(), mediumX, mediumY );
		}
	}
	
//*****************************************************************************
	
	/**
	 * Returns the boundary of the element draw in device units.
	 *
	 * @see   java.awt.geom.GeneralPath
	 *
	 * @return the boundary of the element draw.
	 */
	public GeneralPath getElement() {
		MapElement me = (MapElement)this.getRepresents();
		MapNode[] conec = me.getConnectivite();
		ArrayList<Object> incid = new ArrayList<Object>();
		for (int i=0; i<conec.length; i++) {
			incid.add(conec[i]);
		}
		int sideDeg = incid.size();
		if ( me.getType(1)=='S' ) {
			if ( me.getType(0)=='T' ) {
				sideDeg = (int)(sideDeg/3);
			} else {
				sideDeg = (int)(sideDeg/4);
			}
		} else {
			if ( me.getType(0)=='T' ) {
				sideDeg = (int)(((Math.sqrt(1+8*sideDeg)-1)/2)-1);
			} else {
				sideDeg = (int)(Math.sqrt(sideDeg)-1);
			}
		}
		switch ( sideDeg ) {
			case 2:
				return getElementQuad();
			case 3:
				return getElementCubic();
		}
		return getElementLinear();
	}
	
//*****************************************************************************
	
	/**
	 * Returns the boundary of the element draw in device units.
	 *
	 * @see   java.awt.geom.GeneralPath
	 *
	 * @return the boundary of the element draw.
	 */
	private final GeneralPath getElementLinear() {
		MapElement me = (MapElement)this.getRepresents();
		MapNode[] bound = me.getBoundary();
		GeneralPath element = new GeneralPath();
		int nNodes = bound.length;
		int x = 0;
		int y = 0;
		for (int count = 0; count < nNodes; count++) {
			MapNode mn = bound[count];
			Point p1 = da.getViewPoint( new Point2D.Double(mn.getX(), mn.getY()) );
			if (count==0)
				element.moveTo( (int)p1.getX(),(int)p1.getY() );
			else
				element.lineTo( (int)p1.getX(),(int)p1.getY() );
			x = x + (int)p1.getX();
			y = y + (int)p1.getY();
		}
		mediumX = (int)(x/nNodes) - 5;
		mediumY = (int)(y/nNodes) + 5;
		element.closePath();
		return element;
	}
	
//*****************************************************************************
	
	/**
	 * Returns the boundary of the element draw in device units.
	 *
	 * @see   java.awt.geom.GeneralPath
	 *
	 * @return the boundary of the element draw.
	 */
	private final GeneralPath getElementQuad() {
		MapElement me = (MapElement)this.getRepresents();
		MapNode[] boundary = me.getBoundary();
		ArrayList<Object> bound = new ArrayList<Object>();
		for (int i=0; i<boundary.length; i++) {
			bound.add(boundary[i]);
		}
		bound.add( bound.get(0) );
		GeneralPath element = new GeneralPath();
		int nNodes = 0;
		int xTot = 0;
		int yTot = 0;
		ListIterator nds = bound.listIterator();
		MapNode nd = (MapNode)nds.next();
		Point p1 = da.getViewPoint( nd.getP1() );
		element.moveTo( p1.x, p1.y );
		while(nds.hasNext()) {
			nd = (MapNode)nds.next();
			Point p2 = da.getViewPoint( nd.getP1() );
			nd = (MapNode)nds.next();
			Point p3 = da.getViewPoint( nd.getP1() );
			int x = (int)((4*p2.x-p1.x-p3.x)/2);
			int y = (int)((4*p2.y-p1.y-p3.y)/2);
			element.quadTo( x, y, p3.x, p3.y );
			xTot = xTot + p2.x + p3.x;
			yTot = yTot + p2.y + p3.y;
			nNodes = nNodes + 2;
			p1 = p3;
		}
		mediumX = (int)(xTot/nNodes) - 5;
		mediumY = (int)(yTot/nNodes) + 5;
		element.closePath();
		return element;
	}
	
//*****************************************************************************
	
	/**
	 * Returns the boundary of the element draw in device units.
	 *
	 * @see   java.awt.geom.GeneralPath
	 *
	 * @return the boundary of the element draw.
	 */
	private final GeneralPath getElementCubic() {
		MapElement me = (MapElement)this.getRepresents();
		MapNode[] boundary = me.getBoundary();
		ArrayList<Object> bound = new ArrayList<Object>();
		for (int i=0; i<boundary.length; i++) {
			bound.add(boundary[i]);
		}
		bound.add( bound.get(0) );
		GeneralPath element = new GeneralPath();
		int nNodes = 0;
		int xTot = 0;
		int yTot = 0;
		ListIterator nds = bound.listIterator();
		MapNode nd = (MapNode)nds.next();
		Point p1 = da.getViewPoint( nd.getP1() );
		element.moveTo( p1.x, p1.y );
		while(nds.hasNext()) {
			nd = (MapNode)nds.next();
			Point p2 = da.getViewPoint( nd.getP1() );
			nd = (MapNode)nds.next();
			Point p3 = da.getViewPoint( nd.getP1() );
			nd = (MapNode)nds.next();
			Point p4 = da.getViewPoint( nd.getP1() );
			int x1 = (int)(  (-5*p1.x+18*p2.x-9*p3.x+2*p4.x)/6  );
			int y1 = (int)(  (-5*p1.y+18*p2.y-9*p3.y+2*p4.y)/6  );
			int x2 = (int)(  (+2*p1.x-9*p2.x+18*p3.x-5*p4.x)/6  );
			int y2 = (int)(  (+2*p1.y-9*p2.y+18*p3.y-5*p4.y)/6  );
			element.curveTo( x1, y1, x2, y2, p4.x, p4.y );
			xTot = xTot + p2.x + p3.x + p4.x;
			yTot = yTot + p2.y + p3.y + p4.y;
			nNodes = nNodes + 3;
			p1 = p4;
		}
		mediumX = (int)(xTot/nNodes) - 5;
		mediumY = (int)(yTot/nNodes) + 5;
		element.closePath();
		return element;
	}
	
//*****************************************************************************
}
